Type Graphics

	Const GFX_MAX_HZ% = 60
	
	Const GFX_FULLSCREEN% = False
	
	Const GFX_WIDTH%  = 640
	Const GFX_HEIGHT% = 480
	
	Const FONT_SIZE%  = 12
	Const FONT_PATH$  = "gfx\lucon.ttf"
	Const FONT_FLAGS% = SMOOTHFONT
	
	Const DEFAULT_BG_PATH$ = "gfx\default_bg.png"
	
	Const DEFAULT_MASK_R% = 255
	Const DEFAULT_MASK_G% = 0
	Const DEFAULT_MASK_B% = 255
	
	Const DEFAULT_IMAGE_FLAGS% = MASKEDIMAGE | FILTEREDIMAGE
	
	Const DEFAULT_BLEND% = ALPHABLEND
	
	Global worldCameraX#, worldCameraY#
	
	Global spriteResources:TList = New TList
	Global spriteResourceMap:TMap = CreateMap()
	
	Global spriteEntities:TList = New TList
	
	Global font:TImageFont
	
	Global defaultBGImage:TImage
	
	Function Init%()
	
		worldCameraX# = 0.0
		worldCameraY# = 0.0
		
		GLShareContexts()
		
		SetGraphicsDriver(GLMax2DDriver())
		
		BRL.Graphics.Graphics(GFX_WIDTH, GFX_HEIGHT, GFX_FULLSCREEN * 32, GFX_MAX_HZ)
	
		AutoImageFlags(DEFAULT_IMAGE_FLAGS)
		SetMaskColor(DEFAULT_MASK_R, DEFAULT_MASK_G, DEFAULT_MASK_B)
		
		defaultBGImage = LoadImage(DEFAULT_BG_PATH$)
		
		font = LoadImageFont(FONT_PATH$, FONT_SIZE, FONT_FLAGS)
		SetImageFont(font)
		
		Local gfxDir% = ReadDir("gfx")
		
		If Not gfxDir 
		
			Console.ConsolePrint("Error: Unable to open gfx directory")
			
			Return False
			
		EndIf
		
		Local fileName$ = NextFile$(gfxDir)
		
		While fileName$ <> ""
			
			Local extension$ = Lower$(Right$(fileName$, 4))
			
			If extension$ = ".png"
	
				Local mySpriteResource:SpriteResource = New SpriteResource
	
				mySpriteResource.path$ = "gfx\" + fileName$
									
				Local sprFileName$ = Left$(fileName$, Len(fileName$) - 4) + ".spr"
				Local sprFile:TStream = ReadFile("gfx\" + sprFileName$)
				
				If sprFile
				
					Local sprWidth%  = 0
					Local sprHeight% = 0
					Local sprFrames% = 0
					
					Local sprMaskR% = 255
					Local sprMaskG% = 0
					Local sprMaskB% = 255
					
					Local sprHandleX% = 0
					Local sprHandleY% = 0
					
					Local sprMidhandle% = 0
					
					Local lineNum% = 0
					
					While Not Eof(sprFile)
					
						Local line$ = Lower$(ReadLine$(sprFile))
						
						Local tokens:String[] = Tokenize(line$)
						
						If Left$(tokens[0], 1) <> "#"
						
							Select tokens[0]
							
								Case "dim"
								
									If Len(tokens) <> 4
									
										Console.ConsolePrint("Error loading spr '" + sprFileName$ + "' on line " + String(lineNum) + "@dim, invalid number of parameters")
										
									Else
									
										sprWidth  = tokens[1].ToInt()
										sprHeight = tokens[2].ToInt()
										sprFrames = tokens[3].ToInt()
										
									EndIf
								
								Case "anim"
								
									If Len(tokens) < 4
									
										Console.ConsolePrint("Error loading spr '" + sprFileName$ + "' on line " + String(lineNum) + " @anim, invalid number of parameters")
										
									Else
									
										If sprWidth = 0 Or sprHeight = 0 Or sprFrames = 0
										
											Console.ConsolePrint("Error loading spr '" + sprFileName$ + "' on line " + String(lineNum) + " @anim, valid dimensions must proceed anim")
											
										Else
											
											Local mySpriteAnimation:SpriteAnimation = mySpriteResource.FindAnimation(tokens[1])
											
											If (mySpriteAnimation = Null)
											
												mySpriteAnimation:SpriteAnimation = New SpriteAnimation
											
												mySpriteAnimation.name$  = tokens[1]
												mySpriteAnimation.frames = New Int[Len(tokens) - 3]
												
												mySpriteAnimation.loopFrame = tokens[2].ToInt()
												If mySpriteAnimation.loopFrame < 0 Or mySpriteAnimation.loopFrame >= Len(mySpriteAnimation.frames) Then mySpriteAnimation.loopFrame = 0
												
												For Local f% = 0 To Len(mySpriteAnimation.frames) - 1
												
													mySpriteAnimation.frames[f] = tokens[f + 3].ToInt()
													
													If mySpriteAnimation.frames[f] < 0 Or mySpriteAnimation.frames[f] >= sprFrames Then mySpriteAnimation.frames[f] = 0
													
												Next
												
												mySpriteResource.AddAnimation(mySpriteAnimation)
												
											Else
											
												Console.ConsolePrint("Warning loading spr '" + sprFileName$ + "' on line " + String(lineNum) + " @anim, duplicate anim name '" + tokens[1] + "'")
												
											EndIf
											
										EndIf
											
									EndIf
								
								Case "midhandle"
								
									If Len(tokens) <> 2
									
										Console.ConsolePrint("Error loading spr '" + sprFileName$ + "' on line " + String(lineNum) + " @midhandle, invalid number of parameters")
										
									Else
											
										If tokens[1].ToInt()
										
											sprMidHandle = 1
											
										Else
										
											sprMidHandle = 0
											
										EndIf
										
									EndIf
								
								Case "handle"
								
									If Len(tokens) <> 3
									
										Console.ConsolePrint("Error loading spr '" + sprFileName$ + "' on line " + String(lineNum) + " @handle, invalid number of parameters")
										
									Else
										
										sprMidHandle = 2
										
										sprHandleX = tokens[1].ToInt()
										sprHandleY = tokens[2].ToInt()
										
									EndIf
																	
								Case "mask"
									
									If Len(tokens) <> 4
									
										Console.ConsolePrint("Error loading spr '" + sprFileName$ + "' on line " + String(lineNum) + " @mask, invalid number of parameters")
										
									Else
										
										sprMaskR = tokens[1].ToInt()
										sprMaskG = tokens[2].ToInt()
										sprMaskB = tokens[3].ToInt()
										
									EndIf
								
								Case ""
								
								Default
								
									Console.ConsolePrint("Error loading spr '" + sprFileName$ + "' on line " + String(lineNum) + "@" + String(tokens[0]) + ", unknown command")
																				
							End Select
							
						EndIf
						
						lineNum = lineNum + 1
					
					Wend
					
					CloseFile(sprFile)
					
					If sprWidth = 0 Or sprHeight = 0 Or sprFrames = 0
					
						Console.ConsolePrint("Error loading spr '" + sprFileName$ + "', invalid dimensions")
						
						mySpriteResource.image = LoadImage(mySpriteResource.path$)
						
					Else
					
						If Len(mySpriteResource.animations) = 0
						
							Local mySpriteAnimation:SpriteAnimation = New SpriteAnimation
							
							mySpriteAnimation.name$ = "default"
							mySpriteAnimation.frames = New Int[sprFrames]
							
							For Local f% = 0 To sprFrames - 1
							
								mySpriteAnimation.frames[f] = f
								
							Next
							
							mySpriteResource.AddAnimation(mySpriteAnimation)
							
						EndIf
						
						SetMaskColor(sprMaskR, sprMaskG, sprMaskB)
						
						mySpriteResource.image = LoadAnimImage(mySpriteResource.path$, sprWidth, sprHeight, 0, sprFrames)
						
						If sprMidhandle = 1
						
							MidHandleImage(mySpriteResource.Image)
							
						Else If sprMidHandle = 2
						
							SetImageHandle(mySpriteResource.Image, sprHandleX, sprHandleY)
							
						EndIf
						
						SetMaskColor(DEFAULT_MASK_R, DEFAULT_MASK_G, DEFAULT_MASK_B)
						
					EndIf
							
				Else
				
					mySpriteResource.image = LoadImage(mySpriteResource.path$)
					
				EndIf
				
				If mySpriteResource.image
				
					spriteResources.AddLast(mySpriteResource)
					MapInsert(spriteResourceMap, mySpriteResource.path$, mySpriteResource)
					
				Else
				
					Console.ConsolePrint("Error loading sprite resource '" + mySpriteResource.path$ + "'")
					
				EndIf
				
			EndIf
			
			fileName$ = NextFile$(gfxDir)
			
		Wend
	
		CloseDir(gfxDir)
		
		Return True
		
	End Function
	
	Function Update%()
	
		SetBlend(ALPHABLEND)
		SetColor(255, 255, 255)
		SetTransform(0, 1, 1)
		SetAlpha(1.0)
		
		If Network.netState = Network.STATE_OFFLINE Or Network.netState = Network.STATE_CONNECTING
			
			TileImage(defaultBGImage, System.frameNum, System.frameNum)
			
		Else
		
			SetOrigin(-worldCameraX#, -worldCameraY#)
			
			spriteEntities.Sort(True, _ZCompare)
			
			For Local drawEntity:GameEntity = EachIn spriteEntities
			
				drawEntity.Draw()
				
			Next
			
		EndIf
		
		SetOrigin(0.0, 0.0)
			
		Console.Draw()
		
		Flip
		Cls
	
		Return True
			
	End Function
	
	Function Shutdown%()
	
		spriteResources.Clear()
		ClearMap(spriteResourceMap)
		
		EndGraphics()
		
		Return True
		
	End Function
	
	Function GetSpriteResource:SpriteResource(path$)
	
		Return SpriteResource(MapValueForKey(spriteResourceMap, path$))
		
	End Function
			
	Function _ZCompare%(entity1:Object, entity2:Object)
	
		If GameEntity(entity1).drawZ# < GameEntity(entity2).drawZ# Then Return True
			
		Return False
		
	End Function
	
End Type

Type SpriteAnimation

	Field name$
	
	Field frames%[]
	Field loopFrame%
	
End Type
	
Type SpriteResource Extends Resource

	Field image:TImage
	
	Field animationMap:TMap = CreateMap()
	Field animations:SpriteAnimation[]
	
	Method AddAnimation(animation:SpriteAnimation)
	
		animations = animations[..Len(animations) + 1]
		animations[Len(animations) - 1] = animation
		
		MapInsert(animationMap, animation.name$, animations[Len(animations) - 1])
		
	End Method
	
	Method ClearAnimations()
	
		animations = Null
	
		ClearMap(animationMap)
	
	End Method
		
	Method FindAnimation:SpriteAnimation(name$)
	
		Return SpriteAnimation(MapValueForKey(animationMap, name$))
	
	End Method
	
	Method FindAnimationIndex%(name$)
	
		For Local a% = 0 To Len(animations) - 1
		
			If name$ = animations[a].name$ Then Return a
			
		Next
		
		Return -1
	
	End Method
		
End Type
